package com.richapp.launcher.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.richapp.launcher.common.AdvType;
import com.richapp.launcher.common.HttpResponse;
import com.richapp.launcher.common.UpdatedAdvInfo;
import com.richapp.launcher.dao.adv.Adv;
import com.richapp.launcher.dao.adv.AdvDao;
import com.richapp.launcher.ui.view.ScreenOnAdvView;
import com.richapp.launcher.ui.view.ScreenSaverPicView;
import com.richapp.launcher.utils.DbUtil;
import com.richapp.launcher.utils.HttpUtil;
import com.richapp.launcher.utils.Tools;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by yif on 16/8/2.
 */
public class AdvService extends Service {

    private String tag = AdvService.class.getName();
    private AdvDao advDao = DbUtil.daoSession.getAdvDao();

    private ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(4);

    private final static String BASE_URL = "http://39.108.55.223:8081/ufosmart";
    private final static String URL_CHECK_ADV_UPDATE = BASE_URL + "/adplay/getad?boxCpuId=%s";
    private final static String URL_UPDATE_ADV_PLAY_COUNT = BASE_URL + "/adplay/updateTimes?boxCpuId=%s&id=%s";


    public final String PATH_ADV_FILE = "/data/data/com.richapp.launcher/files" + File.separator + "adv";

    /**
     * 广告资源缓存
     */
    public static final Map<Integer, List<Adv>> advMap = new ConcurrentHashMap<Integer, List<Adv>>();
    /**
     * 广告播放次数缓存
     */
    public static final Map<String, Integer> advPlayCountMap = new ConcurrentHashMap<String, Integer>();

    /**
     * 广告播放待上传队列
     */
    public static final LinkedBlockingQueue<Adv> playedAdvs = new LinkedBlockingQueue<Adv>(1000);

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
//        final String boxCpuId = "1900000000000000";


        final String boxCpuId = Tools.getCPUSerial();
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() { // 10秒更新一次广告
                try {

                    String result = HttpUtil.get(String.format(URL_CHECK_ADV_UPDATE, boxCpuId));
                    HttpResponse<UpdatedAdvInfo> response = JSON.parseObject(result, new TypeReference<HttpResponse<UpdatedAdvInfo>>() {
                    });
                    if (response == null)
                        return;
                    if (response.getCode() == 1010) {
                        updateAdvs(response.getData());
                    }
                } catch (Exception e) {
                    Log.e(tag, e.getMessage(), e);
                }
            }


        }, 0, 10, TimeUnit.SECONDS);

        //        scheduledExecutorService.scheduleAtFixedRate(new Runnable() { //一分钟更新一次广告播放次数
        //            @Override
        //            public void run() {
        //                try {
        //                    //TODO 更新播放次数
        //                } catch (Exception e) {
        //                    Log.e(tag, e.getMessage(), e);
        //                }
        //            }
        //
        //        }, 0, 1, TimeUnit.MINUTES);

        new Thread(new Runnable() { //上传广告播放线程
            @Override
            public void run() {
                while (true) {
                    try {
                        Adv adv = playedAdvs.take();
                        if (adv != null) {
                            String url = String.format(URL_UPDATE_ADV_PLAY_COUNT, boxCpuId, adv.getId());
                            HttpUtil.get(url);
                        }
                    } catch (InterruptedException e) {

                    } catch (Exception e) {
                        Log.e(tag, "更新广告播放次数失败", e);
                    }
                }

            }
        }).start();

        return super.onStartCommand(intent, flags, startId);


    }

    private void updateAdvs(UpdatedAdvInfo info) {
        List<Adv> needDeleteAdvs = new ArrayList<Adv>();
        List<Adv> needInsertAdvs = new ArrayList<Adv>();

        List<Adv> updatedAdvs = new ArrayList<Adv>();
        List<Adv> originalAdvs = new ArrayList<Adv>();


        Adv boot = info.getBoot();
        Adv screenon = info.getScreenon();
        List<Adv> screensaver = info.getScreensaver();
        if (boot != null) {
            boot.setType(AdvType.BOOT_TYPE);
            updatedAdvs.add(boot);
        }
        if (screenon != null) {
            screenon.setType(AdvType.SCREEN_ON_TYPE);
            updatedAdvs.add(screenon);
        }
        if (screensaver != null && !screensaver.isEmpty()) {
            for (Adv adv : screensaver) {
                adv.setType(AdvType.SCREEN_SAVER_TYPE);
            }
            updatedAdvs.addAll(screensaver);
        }

        Adv originalBoot = getBootFromDb();
        Adv originalScreenon = getScreenonFromDb();
        List<Adv> originalScreensaver = getScreensaverFromDb();

        if (originalBoot != null) {
            originalAdvs.add(originalBoot);
        }
        if (originalScreenon != null) {
            originalAdvs.add(originalScreenon);
        }
        if (originalScreensaver != null && !originalScreensaver.isEmpty()) {
            originalAdvs.addAll(originalScreensaver);
        }


        //计算需要删除的广告
        for (Adv adv : originalAdvs) {
            if (!updatedAdvs.contains(adv)) {
                needDeleteAdvs.add(adv);
            }
        }

        //计算需要新增的广告
        for (Adv adv : updatedAdvs) {
            if (!originalAdvs.contains(adv)) {
                needInsertAdvs.add(adv);
            }
        }

        downloadAdvFiles(needInsertAdvs);
        deleteAdvFiles(needDeleteAdvs);
        flushDb(needDeleteAdvs, needInsertAdvs);
        flushCache(needDeleteAdvs, needInsertAdvs);
        if (needDeleteAdvs.size() > 0 || needInsertAdvs.size() > 0)
            notifyAdvsUpdated();
    }

    private void notifyAdvsUpdated() {
        ScreenSaverPicView.needUpdateResources = true;
        ScreenOnAdvView.needUpdateResources = true;
    }

    private void flushCache(List<Adv> needDeleteAdvs, List<Adv> needInsertAdvs) {
        List<Adv> boots = advMap.get(AdvType.BOOT_TYPE);
        List<Adv> screenons = advMap.get(AdvType.SCREEN_ON_TYPE);
        List<Adv> screensavers = advMap.get(AdvType.SCREEN_SAVER_TYPE);

        if (boots == null) {
            boots = new ArrayList<Adv>();
            advMap.put(AdvType.BOOT_TYPE, boots);
        }


        if (screenons == null) {
            screenons = new ArrayList<Adv>();
            advMap.put(AdvType.SCREEN_ON_TYPE, screenons);
        }
        if (screensavers == null) {
            screensavers = new ArrayList<Adv>();
            advMap.put(AdvType.SCREEN_SAVER_TYPE, screensavers);
        }

        for (Adv adv : needDeleteAdvs) {
            if (adv.getType() == AdvType.BOOT_TYPE) {
                boots.remove(adv);
            } else if (adv.getType() == AdvType.SCREEN_ON_TYPE) {
                screenons.remove(adv);
            } else if (adv.getType() == AdvType.SCREEN_SAVER_TYPE) {
                screensavers.remove(adv);
            }
        }

        for (Adv adv : needInsertAdvs) {
            if (adv.getType() == AdvType.BOOT_TYPE) {
                boots.add(adv);
            } else if (adv.getType() == AdvType.SCREEN_ON_TYPE) {
                screenons.add(adv);
            } else if (adv.getType() == AdvType.SCREEN_SAVER_TYPE) {
                screensavers.add(adv);
            }
        }

    }

    private Adv getScreenonFromDb() {
        List<Adv> screenons = listAdvs(AdvType.SCREEN_ON_TYPE);
        if (!screenons.isEmpty()) {
            return screenons.get(0);
        }
        return null;
    }

    private List<Adv> getScreensaverFromDb() {
        List<Adv> screenons = listAdvs(AdvType.SCREEN_SAVER_TYPE);
        return screenons;
    }

    private Adv getBootFromDb() {
        List<Adv> screenons = listAdvs(AdvType.BOOT_TYPE);
        if (!screenons.isEmpty()) {
            return screenons.get(0);
        }
        return null;
    }

    private void flushDb(List<Adv> needDeleteAdvs, List<Adv> needInsertAdvs) {
        for (Adv adv : needDeleteAdvs) {
            advDao.deleteByKey(adv.getId());
        }

        for (Adv adv : needInsertAdvs) {
            advDao.insert(adv);
        }
    }

    private void deleteAdvFiles(List<Adv> needDeleteAdvs) {
        String dir = PATH_ADV_FILE + File.separator;
        for (Adv adv : needDeleteAdvs) {
            File file = new File(dir + adv.getId());
            if (file.exists())
                file.delete();
        }
    }

    private void downloadAdvFiles(List<Adv> needInsertAdvs) {
        File dir = new File(PATH_ADV_FILE + File.separator);
        if (!dir.exists()) {
            dir.mkdir();
        }
        for (Adv adv : needInsertAdvs) {
            InputStream is = null;
            OutputStream os = null;
            try {
                URL url = new URL(BASE_URL + adv.getUrl());
                URLConnection con = url.openConnection();
                is = con.getInputStream();
                byte[] bs = new byte[1024];
                int len;
                os = new FileOutputStream(PATH_ADV_FILE + File.separator + adv.getId());
                while ((len = is.read(bs)) != -1) {
                    os.write(bs, 0, len);
                }
            } catch (Exception e) {
                Log.e(tag, e.getMessage(), e);
            } finally {
                try {
                    if (os != null) {
                        os.close();
                    }
                    if (is != null) {
                        is.close();
                    }
                } catch (Exception e) {

                }
            }
        }
    }

    private List<Adv> listAdvs(int type) {
        return advDao.listAdvs(type);
    }


}
